<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>10.5 Few-shot Prompting（少样本提示） - Langchain框架教程</title>
    <link rel="stylesheet" href="../shared_styles.css">
</head>
<body>
    <div class="container">
        <h1> 第十章：AI系统提示词设计进阶</h1>
        <section id="s10-5">
            <h2>10.5 Few-shot Prompting（少样本提示）</h2>
            <p>Few-shot Prompting（少样本提示）是一种强大的提示词技术，它通过在提示词中包含少量示例（"shots"），来引导大型语言模型（LLM）理解任务并生成符合期望的输出。与Zero-shot Prompting（零样本提示，即不提供任何示例）相比，Few-shot Prompting通常能显著提高模型在特定任务上的表现，尤其是在模型对该任务的理解不够充分时。</p>

            <h3>Few-shot Prompting 的原理</h3>
            <p>LLM在训练过程中接触了海量的文本数据，这使得它们具备了强大的模式识别和泛化能力。当我们提供少量输入-输出示例时，LLM能够识别这些示例中蕴含的模式、任务类型以及期望的输出风格，并将这种模式应用到新的输入上。</p>
            <p>可以理解为，这些示例为LLM提供了一个“迷你”的训练集，帮助模型快速适应一个它可能没有专门训练过的任务。</p>

            <h3>Few-shot Prompting 的应用场景</h3>
            <p>Few-shot Prompting特别适用于以下场景：</p>
            <ul>
                <li><strong>特定格式的文本生成：</strong> 例如，生成符合特定JSON、XML格式的文本，或按照固定模板填充信息。</li>
                <li><strong>情感分析：</strong> 根据示例判断新文本的情感倾向（正面、负面、中立）。</li>
                <li><strong>文本分类：</strong> 根据示例将新文本归类到预定义的类别中。</li>
                <li><strong>信息提取：</strong> 根据示例从非结构化文本中提取特定类型的信息。</li>
                <li><strong>风格迁移：</strong> 根据示例将文本转换为特定的写作风格或语气。</li>
                <li><strong>问答系统：</strong> 根据示例学习如何从给定文本中提取答案。</li>
            </ul>

            <h3>在Langchain中使用 Few-shot Prompting</h3>
            <p>Langchain提供了方便的工具来构建Few-shot Prompting。核心组件是<code>FewShotPromptTemplate</code>。</p>
            <p><code>FewShotPromptTemplate</code>需要以下几个关键元素：</p>
            <ul>
                <li><strong>示例 (Examples):</strong> 一个包含输入-输出对的列表。每个示例都是一个字典，键是输入变量名，值是对应的输入和输出文本。</li>
                <li><strong>示例提示词 (Example Prompt):</strong> 一个用于格式化单个示例的<code>PromptTemplate</code>。它定义了如何将输入和输出变量组合成一个完整的示例字符串。</li>
                <li><strong>前缀 (Prefix):</strong> 在所有示例之前添加的文本，通常用于描述任务或提供通用指令。</li>
                <li><strong>后缀 (Suffix):</strong> 在所有示例之后、用户输入之前添加的文本，通常包含用户输入的占位符。</li>
                <li><strong>示例选择器 (Example Selector, 可选):</strong> 如果示例数量很多，可以使用示例选择器动态选择最相关的少量示例添加到提示词中，以避免超出上下文窗口限制并提高相关性。</li>
            </ul>

            <pre><code class="language-python">
# (接上一节的Qwen LLM初始化代码)
# from langchain_openai import ChatOpenAI
# from langchain_core.prompts import ChatPromptTemplate, SystemMessagePromptTemplate, HumanMessagePromptTemplate
# from langchain_core.output_parsers import StrOutputParser
# import os
#
# api_key = os.environ.get("DASHSCOPE_API_KEY")
# qwen_llm = ChatOpenAI(
#     base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
# key=api_key,
#     model="qwen-plus",
#     temperature=0.1
# )

from langchain_core.prompts import FewShotPromptTemplate, PromptTemplate

# 定义示例
examples = [
    {"input": "高兴", "output": "正面"},
    {"input": "伤心", "output": "负面"},
    {"input": "无聊", "output": "中立"},
    {"input": "兴奋", "output": "正面"},
    {"input": "沮丧", "output": "负面"},
]

# 定义单个示例的提示词格式
example_template = """
输入: {input}
输出: {output}
"""
example_prompt = PromptTemplate(
    input_variables=["input", "output"],
    template=example_template
)

# 创建 FewShotPromptTemplate
few_shot_prompt = FewShotPromptTemplate(
    examples=examples,
    example_prompt=example_prompt,
    prefix="请判断以下词语的情感倾向（正面、负面或中立）：",
    suffix="输入: {adjective}\n输出:",
    input_variables=["adjective"],
    example_separator="\n\n" # 示例之间的分隔符
)

# 格式化提示词
formatted_prompt = few_shot_prompt.format(adjective="惊讶")
print(f"格式化后的提示词:\n{formatted_prompt}")

# 将提示词与LLM连接并调用
chain = few_shot_prompt | qwen_llm | StrOutputParser()

# 测试新的输入
new_adjective = "愤怒"
response = chain.invoke({"adjective": new_adjective})
print(f"\n输入: {new_adjective}")
print(f"AI输出: {response}")

new_adjective_2 = "平静"
response_2 = chain.invoke({"adjective": new_adjective_2})
print(f"\n输入: {new_adjective_2}")
print(f"AI输出: {response_2}")
                    </code></pre>

            <h3>示例选择器 (Example Selectors)</h3>
            <p>当你有大量示例时，将所有示例都包含在提示词中可能会超出LLM的上下文窗口限制，或者稀释了提示词的有效性。Langchain提供了示例选择器来解决这个问题。</p>
            <p>示例选择器根据用户输入与示例的相关性，动态地选择最相关的少量示例。常用的示例选择器包括：</p>
            <ul>
                <li><code>LengthBasedExampleSelector</code>: 根据提示词的长度选择示例，确保总长度不超过限制。</li>
                <li><code>SemanticSimilarityExampleSelector</code>: 使用嵌入模型计算用户输入与示例之间的语义相似度，选择最相似的示例。这需要一个嵌入模型和一个向量存储。</li>
            </ul>

            <pre><code class="language-python">
# (接上一节的Qwen LLM初始化代码)
# from langchain_openai import ChatOpenAI
# from langchain_core.prompts import ChatPromptTemplate, SystemMessagePromptTemplate, HumanMessagePromptTemplate
# from langchain_core.output_parsers import StrOutputParser
# import os
#
# api_key = os.environ.get("DASHSCOPE_API_KEY")
# qwen_llm = ChatOpenAI(
#     base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
# key=api_key,
#     model="qwen-plus",
#     temperature=0.1
# )

# 假设我们有更多的示例
long_examples = [
    {"input": "这部电影太棒了！", "output": "正面"},
    {"input": "我今天心情很好。", "output": "正面"},
    {"input": "这个服务真是糟糕透顶。", "output": "负面"},
    {"input": "我感到非常失望。", "output": "负面"},
    {"input": "天气预报说今天会下雨。", "output": "中立"},
    {"input": "会议定在下午三点。", "output": "中立"},
    {"input": "我爱死这个新功能了！", "output": "正面"},
    {"input": "我对结果很不满意。", "output": "负面"},
]

# 使用 LengthBasedExampleSelector
from langchain.prompts import LengthBasedExampleSelector

example_template_long = """
文本: {input}
情感: {output}
"""
example_prompt_long = PromptTemplate(
    input_variables=["input", "output"],
    template=example_template_long
)

# 创建 LengthBasedExampleSelector，限制最大长度
example_selector = LengthBasedExampleSelector(
    examples=long_examples,
    example_prompt=example_prompt_long,
    max_length=50 # 限制示例的总长度
)

# 创建 FewShotPromptTemplate with Example Selector
few_shot_prompt_selector = FewShotPromptTemplate(
    example_selector=example_selector, # 使用示例选择器
    example_prompt=example_prompt_long,
    prefix="请判断以下文本的情感倾向（正面、负面或中立）：",
    suffix="文本: {text}\n情感:",
    input_variables=["text"],
    example_separator="\n---\n" # 示例之间的分隔符
)

# 测试使用选择器格式化提示词
user_text_selector = "我对这次的更新感到非常兴奋！"
formatted_prompt_selector = few_shot_prompt_selector.format(text=user_text_selector)
print(f"\n使用 LengthBasedExampleSelector 格式化后的提示词:\n{formatted_prompt_selector}")

# 使用 SemanticSimilarityExampleSelector (需要安装相关库并配置嵌入模型和向量存储)
# from langchain.prompts import SemanticSimilarityExampleSelector
# from langchain_community.embeddings import QianfanEmbeddingsEndpoint # 以千帆为例，需要替换为Qwen支持的嵌入模型
# from langchain_community.vectorstores import Chroma # 以Chroma为例，需要替换为Qwen支持的向量存储

# # 假设已经配置好嵌入模型和向量存储
# # embeddings = QianfanEmbeddingsEndpoint(...)
# # vectorstore = Chroma.from_examples(long_examples, embeddings, ...)

# # example_selector_semantic = SemanticSimilarityExampleSelector(
# #     vectorstore=vectorstore,
# #     k=2 # 选择最相似的2个示例
# # )

# # few_shot_prompt_semantic = FewShotPromptTemplate(
# #     example_selector=example_selector_semantic,
# #     example_prompt=example_prompt_long,
# #     prefix="请判断以下文本的情感倾向（正面、负面或中立）：",
# #     suffix="文本: {text}\n情感:",
# #     input_variables=["text"],
# #     example_separator="\n---\n"
# # )

# # user_text_semantic = "这个产品完全不符合我的预期。"
# # formatted_prompt_semantic = few_shot_prompt_semantic.format(text=user_text_semantic)
# # print(f"\n使用 SemanticSimilarityExampleSelector 格式化后的提示词:\n{formatted_prompt_semantic}")
                    </code></pre>
            <p>使用示例选择器可以使Few-shot Prompting更加灵活和高效。</p>

            <h3>Few-shot Prompting 的注意事项</h3>
            <ul>
                <li><strong>示例质量：</strong> 提供的示例质量至关重要。清晰、准确且具有代表性的示例能更好地引导LLM。</li>
                <li><strong>示例数量：</strong> “Few-shot”意味着少量示例。通常3-5个示例就足够了，过多的示例可能会导致上下文窗口溢出或模型混淆。</li>
                <li><strong>示例多样性：</strong> 示例应尽可能覆盖任务的常见变化和边界情况。</li>
                <li><strong>示例顺序：</strong> 示例的顺序有时也会影响模型表现，可以尝试不同的顺序。</li>
                <li><strong>与指令结合：</strong> Few-shot Prompting通常与清晰的指令（在Prefix中）结合使用，以进一步明确任务要求。</li>
            </ul>

            <h3>总结</h3>
            <p>Few-shot Prompting是一种通过提供少量示例来提高LLM在特定任务上表现的有效技术。Langchain的<code>FewShotPromptTemplate</code>及其示例选择器提供了便捷的方式来构建和管理Few-shot提示词。通过精心设计示例和结合清晰的指令，我们可以利用Few-shot Prompting构建更加智能和鲁棒的AI应用。</p>
        </section>

        <div class="navigation">
            <a href="../langchain_tutorial_outline.html">返回教程目录</a>
            <a href="../chapter10/chapter10_4_controlling_output_format.html">&larr; 上一节：10.4 控制输出格式和结构</a>
            <a href="../chapter10/chapter10_6_chain_of_thought.html">下一节：10.6 Chain-of-Thought Prompting（思维链提示） &rarr;</a>
        </div>
    </div>
</body>
</html>
